<?php
namespace Abo\Larasearch\V0\SyncDatabase\Logic;

use Abo\Generalutil\V1\Repositories\BaseRepository;
use Illuminate\Support\Facades\DB;

/**
 * 同步差异数据逻辑
 * Description:
 * Class SyncDifferenceDataLogic
 * @package Abo\Larasearch\SyncDatabase\Logic
 */
class SyncChangeDataLogic
{
    const NO_SYNC_LOG_STATUS = 0; // 未同步
    const SYNCED_LOG_STATUS = 1; // 已同步

    const CHANGE_TYPE_INSERT = 'INSERT';
    const CHANGE_TYPE_UPDATE = 'UPDATE';
    const CHANGE_TYPE_DELETE = 'DELETE';

    protected $syncDate, $targetTableName;
    protected $changeTypeArr = [
        self::CHANGE_TYPE_INSERT,
        self::CHANGE_TYPE_UPDATE,
        self::CHANGE_TYPE_DELETE,
    ];

    public function __construct( string $targetTableName, string $syncDate = '' )
    {
        $this->setSyncData( $syncDate );
        $this->setTargetTableName( $targetTableName );
    }

    /**
     * 设置同步状态 已同步
     * @param string $changeType 同步类型
     * @param array $where 筛选条件 支持数组
     * @return mixed
     */
    protected function setSyncStatusDone( string $changeType = '', array $where )
    {
        // 更新上一秒之前数据 => 这一秒更新数据下一次仍会更新( 避免卡点 )
        $syncDate = date( 'Y-m-d H:i:s', ( strtotime( $this->syncDate ) - 1 ) );

        $Model = DB::table( $this->targetTableName )
            ->where( 'created_at', '<=', $syncDate )
            ->where( 'sync_status', '=', self::NO_SYNC_LOG_STATUS );

        if ( in_array( $changeType, $this->changeTypeArr ) ) {
            $Model = $Model->where( 'type', '=', $changeType );
        }
        if ( $where && is_array( $where ) ) {

            foreach ( $where as $k2Where => $v2Where ) {
                if ( is_array( $v2Where ) ) {
                    $Model = $Model->whereIn( $k2Where, $v2Where );
                }else{
                    $Model = $Model->where( $k2Where, '=', $v2Where );
                }
            }

        }

        return $Model->update( [ 'sync_status' => self::SYNCED_LOG_STATUS ] );
    }

    /**
     * 未同步数据记录
     * @param string $changeType 同步类型
     * @param array $where 筛选条件
     * @param array $paginate 分页信息: [ 'page' => 1, 'size' => 100, 'is_count' => false ] 支持分页&是否统计
     * @return array|int
     */
    protected function noSyncDataLog( string $changeType, array $where, array $paginate )
    {
        if ( !in_array( $changeType, $this->changeTypeArr ) ) {
            return [];
        }

        $SearchModel = DB::table( $this->targetTableName )
            ->where( 'created_at', '<=', $this->syncDate )
            ->where( 'sync_status', '=', self::NO_SYNC_LOG_STATUS )
            ->where( 'type', '=', $changeType );

        if ( is_array( $where ) && $where ) {
            foreach ( $where as $k2Where => $v2Where ) {
                $SearchModel = $SearchModel->where( $k2Where, $v2Where );
            }
        }

        if ( isset( $paginate[ 'page' ] ) && $paginate[ 'page' ] ) {
            $pageNum = isset( $paginate[ 'size' ] ) ? $paginate[ 'size' ] : 500;
            $SearchModel = $SearchModel->forPage( intval( $paginate[ 'page' ] ), intval( $pageNum ) );
        }

        if ( isset( $paginate[ 'is_count' ] ) && $paginate[ 'is_count' ] ) {
            return $SearchModel->count();
        }else{
            $SearchModel = $SearchModel->pluck( 'change_id', 'id' );
        }

        if ( false === $SearchModel ) { return []; }
        return $SearchModel->toArray();
    }

    /**
     * 设置同步目标表
     * @param string $targetTableName 表名
     * @return string
     * @throws \Exception
     */
    private function setTargetTableName( string $targetTableName )
    {
        if ( !$targetTableName ) {
            throw new \Exception( '变更记录表 未设置', false );
        }

        return $this->targetTableName = $targetTableName . '_change_log';
    }

    /**
     * 设置同步时间
     * @param string $syncDate 同步日期
     * @return false|string
     */
    private function setSyncData( $syncDate )
    {
        $this->syncDate = date( 'Y-m-d H:i:s' );
        if ( $syncDate ) {
            $this->syncDate = date( 'Y-m-d H:i:s', strtotime( $syncDate ) );
        }

        return $this->syncDate;
    }
}